package com.AAVSO.Silvis.EggenCard2.client;

import java.util.Date;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.http.client.URL;
import com.google.gwt.i18n.client.NumberFormat;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class EggenCard2 implements EntryPoint {

	private VerticalPanel mainPanel = new VerticalPanel();
	final TextBox usernameField= new TextBox();
	final PasswordTextBox passwordField= new PasswordTextBox();
	final Button signinButton= new Button("Sign in");
	private int userID= 0;
	final Label ECtotal= new Label("Total:");
	private float EChrsTotal, EChrsSessionStart;
	final Label ECsession= new Label("Session:");
	private int   ECcntTotal, ECcntSession;
	// Select batch of cards
	final TextBox boxField = new TextBox();
	final TextBox bundleField = new TextBox();
	final TextBox pdfField = new TextBox();
	final TextBox pageField = new TextBox();
	final TextBox classField = new TextBox();
	final TextBox colorField = new TextBox();
	final TextBox cardkeyField = new TextBox();
	final TextBox starnameField= new TextBox();
	final Button requestCardButton = new Button("Request");
	final Label resultCountLabel = new Label();
	final Label error2Label = new Label();
	int cardMax= 0, cardIndex, callnum; 
    // Edit Card
	final Button prevCardButton= new Button("Prev");
	final Button nextCardButton= new Button("Next");
	final Label icardnumberLabel = new Label();
	final Label icardnameLabel = new Label();
	final TextBox icolorField = new TextBox();
	final TextBox iorientField = new TextBox();
	final TextBox iclassField = new TextBox();
	final Button iupdateButton= new Button("Update");
	final TextBox inoteField = new TextBox();
    final Image iCardImage= new Image();	
	// stars
	private VerticalPanel starPanel = new VerticalPanel();
	private FlexTable starsTable = new FlexTable();
	private HorizontalPanel addStarPanel = new HorizontalPanel();
	private TextBox newStarTextBox = new TextBox();
	private Button addStarButton = new Button("Add");
	private Button checkStarButton = new Button("Check");
	
	private static final String BASE_URL 
    	= "http://www.gasilvis.com/EggenCard2/";
	private int jsonRequestId = 0;

	/**
	 * Cast JavaScriptObject as JsArray of StockData.
	 */
	private final native JsArray<CardRefData> card(JavaScriptObject jso)/*-{ return jso; }-*/;  
	private JavaScriptObject jcard;
	private CardRefData crd;
	private final native JsArray<StarData> star(JavaScriptObject jso)/*-{ return jso; }-*/;  
	private JavaScriptObject jstar;
	private StarData srd;
	private final native JsArray<UserData> user(JavaScriptObject jso)/*-{ return jso; }-*/;  
	private JavaScriptObject juser;
	private UserData urd;
	

	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
		// Associate the Main panel with the HTML host page.
		RootPanel.get("EggenProject").add(mainPanel);
		// login section
		RootPanel.get("usernameContainer").add(usernameField);
		RootPanel.get("passwordContainer").add(passwordField);
		RootPanel.get("signinButtonContainer").add(signinButton);
		RootPanel.get("ECsession").add(ECsession);
		RootPanel.get("ECtotal").add(ECtotal);
        // batch section
		RootPanel.get("boxFieldContainer").add(boxField);
		boxField.setVisibleLength(3);
		RootPanel.get("bundleFieldContainer").add(bundleField);
		bundleField.setVisibleLength(3);
		RootPanel.get("pdfFieldContainer").add(pdfField);
		pdfField.setVisibleLength(3);
		RootPanel.get("pageFieldContainer").add(pageField);
		pageField.setVisibleLength(3);
		RootPanel.get("classFieldContainer").add(classField);
		classField.setVisibleLength(3);
		RootPanel.get("colorFieldContainer").add(colorField);
		colorField.setVisibleLength(3);
		RootPanel.get("cardkeyFieldContainer").add(cardkeyField);
		cardkeyField.setVisibleLength(6);
		RootPanel.get("starnameFieldContainer").add(starnameField);
		starnameField.setVisibleLength(10);
		RootPanel.get("requestCardButtonContainer").add(requestCardButton);
		RootPanel.get("resultCountLabelContainer").add(resultCountLabel);
		RootPanel.get("error2LabelContainer").add(error2Label);
		// card section
		RootPanel.get("prevCardButtonContainer").add(prevCardButton);
		RootPanel.get("nextCardButtonContainer").add(nextCardButton);
		RootPanel.get("cardnumberLabelContainer").add(icardnumberLabel);
		RootPanel.get("cardnameLabelContainer").add(icardnameLabel);
		RootPanel.get("icolorFieldContainer").add(icolorField);
		icolorField.setVisibleLength(3);
		icolorField.setTitle("blank is White\nB for blue\nG for green\nR is red or pink\nY for yellow");
		RootPanel.get("iorientationFieldContainer").add(iorientField);
		iorientField.setVisibleLength(3);
		iorientField.setTitle("1 rotate right 90\n2 rotate left 90\n3 rotate 180");
		RootPanel.get("iclassFieldContainer").add(iclassField);
		iclassField.setVisibleLength(3);
		iclassField.setTitle("N not processed\nD for done\nR for needs review\nB for blank\nS for special(add note)");
		RootPanel.get("inoteFieldContainer").add(inoteField);
		inoteField.  setWidth("50em");
		RootPanel.get("iupdateButtonContainer").add(iupdateButton);
		iupdateButton.setEnabled(false);
		RootPanel.get("cardImage").add(iCardImage);

		//stars
	    starsTable.setText(0, 0, "Star");
	    // Assemble Add Star panel.
	    addStarPanel.add(newStarTextBox);
	    //newStarTextBox.setStyleName("textboxupper");//  .setStyleAttribute("textTransform", "uppercase");
	    addStarPanel.add(checkStarButton);
	    addStarPanel.add(addStarButton);
		addStarButton.setEnabled(false);
	    starPanel.add(starsTable);
	    starPanel.add(addStarPanel);
	    RootPanel.get("starPanelContainer").add(starPanel);
	    
	    signinButton.addClickHandler(new ClickHandler() { 
	    	public void onClick(ClickEvent event) {
	    		String q= BASE_URL+ "Name.php?UserName="+URL.encodeQueryString(usernameField.getText())
	    		  	+"&password="+URL.encodeQueryString(passwordField.getText())
    		    	+"&callback=";
          
	    		JSONRequest.get(q, new JSONRequestHandler() {
	    			@Override
	    			public void onRequestComplete(JavaScriptObject json) {
	    				juser= json;
	    				if(1== user(juser).length()) { // OK
	    					urd= user(juser).get(0);
	    					if(urd.getUserID() != userID) {
		    					userID= urd.getUserID();
		    					EChrsTotal= urd.getEChrs();
		    					ECcntTotal= urd.getECcnt();
		    					iupdateButton.setEnabled(true);
		    					addStarButton.setEnabled(true);
		    					EChrsSessionStart= getTimeHrs();
		    					ECcntSession= 0;
	    					}
	    				} else { // not recognized
	    					userID= 0;
	    					EChrsTotal= 0;
	    					ECcntTotal= 0;
	    					iupdateButton.setEnabled(false);
	    					addStarButton.setEnabled(false);
	    					EChrsSessionStart= getTimeHrs();
	    					ECcntSession= 0;
	    				}
	    				updateEC();
	    			}
	    		});
	    	}
	    });
	    
		// Fired when the user clicks on the requestCardButton.
		requestCardButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				requestCardButton.setText("Stand by");
				requestCards();
			}
		});
		
		prevCardButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
                if(cardMax!=0){
                	if(cardIndex> 0) { 
                		cardIndex--;
                		crd= card(jcard).get(cardIndex);
                		showCard();
                	}
                }
			}
		});

		nextCardButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
                if(cardMax!=0){
                	if(cardIndex< cardMax-1) { 
                		cardIndex++;
                		crd= card(jcard).get(cardIndex);
                		showCard();
                	}
                }
			}
		});

		iupdateButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				iCardImage.setUrl("");//BASE_URL+"CardImage.php?CardKey=102902"); // blank card
				// did the card class change?
				String newClass= iclassField.getText().trim().toUpperCase() +"N";
				newClass= newClass.substring(0,1);
				if(!newClass.equals(""+crd.getClassification())) {
					if(!newClass.equals("N")) { // get credit for change
						ECcntSession++;
					} else { // get dis credit
						ECcntSession--;
					}
				}
				// clean inputs
				iclassField.setText(newClass);
				icolorField.setText(icolorField.getText().trim().toUpperCase());
	            iCardImage.setUrl(BASE_URL+"CardImage.php?CardKey="+(""+crd.getCardKey())
	            		+"&orientation="+iorientField.getText()
	            		+"&color="+icolorField.getText() 
	            		+"&note="+URL.encodeQueryString(inoteField.getText())    
	            		+"&class="+iclassField.getText()
	            		+"&echrs="+(""+ (EChrsTotal+ (getTimeHrs()- EChrsSessionStart)))
	            		+"&eccnt="+(""+ (ECcntTotal+ ECcntSession))
	            		+"&userid="+(""+ userID)
	            		+"&callnum="+callnum++  // to defeat cache
	            		);
	            // save locally
	            crd.setClassification(iclassField.getText());
	            crd.setColor(icolorField.getText());
	            crd.setNote(URL.encodeQueryString(inoteField.getText()));
	            crd.setOrientation(Integer.parseInt(iorientField.getText()));
	            card(jcard).set(cardIndex, crd);
	            updateEC();
				
			}
		});

	    checkStarButton.addClickHandler(new ClickHandler() {
	    	public void onClick(ClickEvent event) {
	    		gotoSimbad(newStarTextBox.getText());
	    	}
	    });

	    // Fired when the user clicks on the adding a star
		addStarButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				iclassField.setText("d"); // anticipation
				iupdateButton.setFocus(true);
				// check format of star name
				String sr= newStarTextBox.getText().trim().toUpperCase();
//				if(sr.equals(sr.toUpperCase().replaceAll("\\s",""))) {
//					displayError("");
//				} else {
//					displayError("Star has embedded blanks. Please fix or use an alias.");
//				}
	            while(1 < starsTable.getRowCount()) starsTable.removeRow(1); // clear table
	    		String q= BASE_URL+ "Stars.php?CardKey="+(""+crd.getCardKey())
	    		    +"&StarName="+URL.encodeQueryString(sr)
	    		    +"&UserID="+(""+userID)
	    		    +"&callback=";
	          
	    		JSONRequest.get(q, new JSONRequestHandler() {
	    			@Override
	    			public void onRequestComplete(JavaScriptObject json) {
	    				onStarRequestComplete(json);
	    			}
	    		});
			}	
		});

	} // onModuleLoad

	private void updateEC() {
	   float x= getTimeHrs()-EChrsSessionStart;
	   ECsession.setText("Session: "
			   +NumberFormat.getFormat("###0.0").format(x)+ " hrs, "
			   +NumberFormat.getFormat("###0").format(ECcntSession)+ " cards");
	   ECtotal.setText("Total:   "
			   +NumberFormat.getFormat("###0.0").format(EChrsTotal+ x)+ " hrs, "
			   +NumberFormat.getFormat("###0").format(ECcntTotal+ ECcntSession)+ " cards");
	}
	
	private void requestCards() {
		// build the string
		String boxF= boxField.getText();
		String bundleF= bundleField.getText();
		String pdfF= pdfField.getText();
		String pageF= pageField.getText();
		String classF= classField.getText();
		String colorF= colorField.getText();
        String cardkeyF= cardkeyField.getText();		
		String starnameF= starnameField.getText();
		if(boxF.length()!=0) {
			boxF= "Box=" +boxF + "&";
		}
		if(bundleF.length()!=0) {
			bundleF= "Bundle=" +bundleF + "&";
		}
		if(pdfF.length()!=0) {
			pdfF= "PDF=" +pdfF + "&";
		}
		if(pageF.length()!=0) {
			pageF= "Page=" +pageF + "&";
		}
		if(classF.length()!=0) {
			classF= "Classification=" +classF + "&";
		}
		if(colorF.length()!=0) {
			colorF= "Color=" +colorF + "&";
		}
		if(cardkeyF.length()!=0) {
			cardkeyF= "CardKey=" +cardkeyF + "&";
		}
		if(starnameF.length()!=0) {
			starnameF= "StarName=" +URL.encodeQueryString(starnameF) + "&";
		}
		String q= BASE_URL+ "DBquery.php?" 
		   +boxF +bundleF +pdfF +pageF +classF +colorF +cardkeyF +starnameF
		   +"callback=";

        JSONRequest.get(q, new JSONRequestHandler() {
			@Override
			public void onRequestComplete(JavaScriptObject json) {
				requestCardButton.setText("Request");
				jcard= json;
				cardMax= card(jcard).length();
				resultCountLabel.setText(""+cardMax);
				cardIndex= 0;
				showCard();
			}
        });
	}

    private void showCard() {
    	if(cardMax!=0) {
    		icardnumberLabel.setText(""+(1+cardIndex));
    		crd= card(jcard).get(cardIndex);
    		icardnameLabel.setText(crd.getBox()+"/"+ crd.getBundle()+"/"+ crd.getPDF()+"/"+crd.getPage());
            icolorField.setText(crd.getColor());
            iorientField.setText(""+crd.getOrientation());
            iclassField.setText(crd.getClassification());
            inoteField.setText(URL.decodeQueryString(crd.getNote()));
            
            String c= BASE_URL+"CardImage.php?CardKey="+(""+crd.getCardKey())+"&orientation="+(""+crd.getOrientation());
            // set image url to get and display card
            iCardImage.setUrl(c);
            /*
            c= c+ "&name=Card"+name+".jpg&callback=";
            JSONRequest.get(c, new JSONRequestHandler() {
            	@Override
            	public void onRequestComplete(JavaScriptObject json) {
            		iCardImage.setUrl(BASE_URL+ "Card"+ name+ ".jpg?num="+ (""+ callnum++));
            	}
            });
            */
            // get stars
            while(1 < starsTable.getRowCount()) starsTable.removeRow(1); // clear table
    		String q= BASE_URL+ "Stars.php?CardKey="+(""+crd.getCardKey())+"&callback=";
          
    		JSONRequest.get(q, new JSONRequestHandler() {
    			@Override
    			public void onRequestComplete(JavaScriptObject json) {
    				onStarRequestComplete(json);
    			}
    		});
            
    	}
    }

	private void onStarRequestComplete(JavaScriptObject json) {
		jstar= json;
		for(int i= 0; i< star(jstar).length(); i++) {
			srd= star(jstar).get(i);
			if(i==0) { // look for msg in first reference
				displayError(URL.decodeQueryString(srd.getNote()));
			} else {
				starsTable.setText(i+1, 0, URL.decodeQueryString(srd.getStarName()));
				// Add a button to check this star from the table.
				Button checkStarButton = new Button("Check");
				checkStarButton.addClickHandler(new ClickHandler() {
					public void onClick(ClickEvent event) {
						int rowIndex = starsTable.getCellForEvent(event).getRowIndex();
						gotoSimbad(starsTable.getText(rowIndex, 0));
					}
				});
				starsTable.setWidget(i+1, 1, checkStarButton);
				// Add a button to remove this star from the table.
				Button removeStarButton = new Button("Remove");
				if(userID==0) removeStarButton.setEnabled(false);
				removeStarButton.addClickHandler(new ClickHandler() {
					public void onClick(ClickEvent event) {
						int rowIndex = starsTable.getCellForEvent(event).getRowIndex();
						while(1 < starsTable.getRowCount()) starsTable.removeRow(1); // clear table
						String q= BASE_URL+ "Stars.php?StarKey="+(""+star(jstar).get(rowIndex-1).getStarKey())
							 +"&CardKey="+(""+crd.getCardKey())
                             +"&callback=";
			          
						JSONRequest.get(q, new JSONRequestHandler() {
							@Override
							public void onRequestComplete(JavaScriptObject json) {
								onStarRequestComplete(json);
							}
						});
					}	
				});
				starsTable.setWidget(i+1, 2, removeStarButton);
			}
		}	
	}
    
	private void gotoSimbad(String starRef) {
		String q= URL.encodeQueryString(starRef);
		Window.open("http://simbad.harvard.edu/simbad/sim-basic?Ident="+q, "_blank", "");
	}
    
	private float getTimeHrs() {
		Date date = new Date();
		return((float) (date.getTime() / 3600000.0));
	}	
     

	// save to sort out a timeout
	public native static void getJson(int requestId, String url, EggenCard2 handler)
	/*-{
  	     var callback = "phfoo" + requestId;

  	     	// [1] Create a script element.
  	     	var script = document.createElement("script");
  	     	script.setAttribute("src", url+callback);
  	     	script.setAttribute("type", "text/javascript");
  	     	// [2] Define the callback function on the window object.
  	     	window[callback] = function(jsonObj) {
  	     		// [3]
  	       		handler.@com.AAVSO.Silvis.EggenCard2.client.EggenCard2::DBqueryResponse(Lcom/google/gwt/core/client/JavaScriptObject;)(jsonObj);
  	       		window[callback + "done"] = true;
  			}

  	     	// [4] JSON download has 10-second timeout.
  	     	setTimeout(function() {
  	       		if (!window[callback + "done"]) {
  	         		handler.@com.AAVSO.Silvis.EggenCard2.client.EggenCard2::DBqueryResponse(Lcom/google/gwt/core/client/JavaScriptObject;)(null);
  	       		}	

  	       		// [5] Cleanup. Remove script and callback elements.
  	       		document.body.removeChild(script);
  	       		delete window[callback];
  	       		delete window[callback + "done"];
  	     		}, 10000);

  	     	// [6] Attach the script element to the document body.
  	     	document.body.appendChild(script);
  	    }-*/;
	
	/**
	 * Handle the response to the request for CardRef data from a remote server.
	 */
	public void DBqueryResponse(JavaScriptObject jso) {
		requestCardButton.setText("Request");
		if (jso == null) {
			displayError("Couldn't retrieve JSON");
			return;
		}

		resultCountLabel.setText(""+card(jso).length());
		

	} 

	/**
	 * If can't get JSON, display error message.
	 * @param error
	 */
	protected void displayError(String error) {
		
		error2Label.setText(error);
		//error2Label.setVisible(true);
	}

}
